package com.smasher.nfc.protocol.mifare

import android.annotation.SuppressLint
import android.nfc.Tag
import android.nfc.tech.MifareClassic
import android.nfc.tech.TagTechnology
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import com.smasher.nfc.util.Converter
import java.io.IOException
import kotlin.math.min

class MifareHelper {

    private fun closeTagTechnology(technology: TagTechnology) {
        try {
            technology.close()
        } catch (e: Exception) {
            Log.e(TAG, "close tag technology: ", e)
        }
    }

    fun readMifareClassic(tag: Tag) {
        val mfc = MifareClassic.get(tag) ?: return
        object : Thread() {
            override fun run() {
                try {
                    closeTagTechnology(mfc)
                    mfc.connect()
                    mfc.use {
                        val secCount: Int = mfc.sectorCount
                        val mifareClassCard = MifareClassCard(secCount)
                        for (j in 0 until secCount) {
                            val mifareSector = MifareSector()
                            mifareSector.sectorIndex = j
                            val auth = try {
                                mfc.authenticateSectorWithKeyA(j, MifareClassic.KEY_DEFAULT)
                            } catch (e: IOException) {
                                e.printStackTrace()
                                false
                            }
                            mifareSector.authorized = auth

                            if (auth) {
                                val bCount = min(
                                    mfc.getBlockCountInSector(j).toDouble(),
                                    MifareSector.BLOCKCOUNT.toDouble()
                                ).toInt()
                                var bIndex = mfc.sectorToBlock(j)
                                for (i in 0 until bCount) {
                                    // 6.3) Read the block
                                    var data = ByteArray(0)
                                    try {
                                        data = mfc.readBlock(bIndex)
                                    } catch (e: IOException) {
                                        Log.e(TAG, "run: ", e)
                                    }
                                    val mifareBlock = MifareBlock(data)
                                    mifareBlock.blockIndex = bIndex
                                    bIndex++
                                    mifareSector.blocks[i] = mifareBlock
                                }
                                mifareClassCard.setSector(
                                    mifareSector.sectorIndex,
                                    mifareSector
                                )
                            }
                        }
                        handler2.sendMessage(Message().apply {
                            obj = mifareClassCard
                            what = WHAT_CARD
                        })

                        val blockData = ArrayList<String>()
                        var blockIndex = 0
                        for (i in 0 until secCount) {
                            val mifareSector: MifareSector = mifareClassCard.getSector(i)
                            for (j in 0 until MifareSector.BLOCKCOUNT) {
                                val mifareBlock = mifareSector.blocks[j]
                                val data = mifareBlock.data
                                blockData.add(
                                    "Block " + blockIndex++ + " : " + Converter.getHexString(
                                        data,
                                        data.size
                                    )
                                )
                            }
                        }
                        handler2.sendMessage(Message().apply {
                            obj = blockData
                            what = WHAT_BLOCK
                        })
                    }
                } catch (e: Exception) {
                    Log.e(TAG, "run: ", e)
                }
            }
        }.start()
    }

    @SuppressLint("HandlerLeak")
    private val handler2: Handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                WHAT_BLOCK -> {
                    val contents = msg.obj as ArrayList<*>
                    for (item in contents) {
                        Log.d(TAG, item.toString())
                    }
                }

                WHAT_CARD -> {
                    val loong = msg.obj as MifareClassCard
                    Log.d(TAG, loong.toString())
                }

                else -> {}
            }
        }
    }

    companion object {
        const val WHAT_BLOCK = 1005
        const val WHAT_CARD = 1132
        const val TAG = "Mifare"
    }

}
